/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#ifndef OBS_INDEX_H
#define OBS_INDEX_H

#include <memory>
#include <future>
#include "BasicJob.h"
#include "Module/src/common/JsonHelper.h"
#include "obs_common/ObjectStorageCommonService.h"
#include "log/Log.h"
#include "utils/PluginUtilities.h"

namespace OBSPlugin {
enum class OBSIndexJobType {
    OBS_INDEX_TYPE_FULL,
    OBS_INDEX_TYPE_INC
};

class ObjectStorageIndexJob : public ObjectStorageCommonService {
public:
    ObjectStorageIndexJob() {}
    ~ObjectStorageIndexJob()
    {
        INFOLOG("Object storage index deconstruct!");
    }

    EXTER_ATTACK int PrerequisiteJob() override;
    EXTER_ATTACK int GenerateSubJob() override;
    EXTER_ATTACK int ExecuteSubJob() override;
    EXTER_ATTACK int PostJob() override;

private:
    struct StorageRepositoryExtendInfo {
        bool isCurrentCopyRepo{};
        int timestamp{};
        std::string copyId;
        std::string fsId;

        BEGIN_SERIAL_MEMEBER
        SERIAL_MEMBER_TO_SPECIFIED_NAME(isCurrentCopyRepo, isCurrentCopyRepo);
        SERIAL_MEMBER_TO_SPECIFIED_NAME(timestamp, timestamp);
        SERIAL_MEMBER_TO_SPECIFIED_NAME(copyId, copyId);
        SERIAL_MEMBER_TO_SPECIFIED_NAME(fsId, fsId);
        END_SERIAL_MEMEBER
    };

    struct RfiGeneratationParam {
        std::string copyId;
        std::vector<std::string> rfiFiles;

        BEGIN_SERIAL_MEMEBER
        SERIAL_MEMBER_TO_SPECIFIED_NAME(copyId, copyId)
        SERIAL_MEMBER_TO_SPECIFIED_NAME(rfiFiles, rfiFiles)
        END_SERIAL_MEMEBER
    };

    int PrerequisiteJobInner();
    int GenerateSubJobInner();
    int ExecuteSubJobInner();
    int PostJobInner();

    bool StartScanner();
    void ReportJob(AppProtect::SubJobStatus::type status);
    std::shared_ptr<AppProtect::BuildIndexJob> GetJobInfoBody();

    int IdentifyRepos();
    int IdentifyRepo(AppProtect::StorageRepository& repo);
    int ProcessFullObsIndex();
    int ProcessIncObsIndex();
    bool CheckAllBucketsDcacheExist(std::string metaFilePath);
    bool CheckDcacheExist(std::string metaFilePath) const;
    void PrepareForGenrateRfi(std::string preMetaFilePath, std::string curMetafilepath);
    bool UnzipCurMetafileToWorkDir(const std::string& bucketPath);
    bool UnzipPreMetafileToWorkDir(const std::string& bucketPath);
    int GenerateAllBucketsFullRfiInPath();
    int GenerateFullRfiInPath(const std::string& path, bool isPre);
    void UnzipMetafileToCurPathAndRemoveAsync(const std::string& path, std::promise<int>& promiseObj);
    void FillScanConfigForGenerateRfi(const std::string& prevDcachePath,
        const std::string& curDcachePath, bool isLastScan, bool isPre);
    SCANNER_STATUS MonitorScanner();
    static void GeneratedCopyCtrlFileCb(void *usrData, std::string ctrlFile);
    static void GeneratedHardLinkCtrlFileCb(void *usrData, std::string ctrlFile);
    static void GenerateRfiCtrlFileCb(void *usrData, RfiCbStruct cbParam);
    void GetBucketPath(const std::string& metaFilePath, std::vector<std::string>& bucketPathList);
    int ProcessIncHostIndexForPrefix(const std::vector<std::string>& curDirList,
        const std::vector<std::string>& prevDirList);
    int ProcessIncHostIndexForRemainPrefix(std::queue<std::string>& curQueue, std::queue<std::string>& prevQueue);
    void CheckIsLastScan(const std::queue<std::string>& curQueue,
        const std::queue<std::string>& preQueue);
    int GenerateIncRfiInPath(const std::string& prevPath,
        const std::string& curPath);

    std::shared_ptr<AppProtect::BuildIndexJob> m_indexPara = nullptr;
    std::shared_ptr<AppProtect::StorageRepository> m_cacheRepo = nullptr;
    std::shared_ptr<AppProtect::StorageRepository> m_preRepo = nullptr;
    std::shared_ptr<AppProtect::StorageRepository> m_curRepo = nullptr;
    std::shared_ptr<AppProtect::StorageRepository> m_indexRepo = nullptr;
    std::shared_ptr<AppProtect::StorageRepository> m_metaRepo = nullptr;
    std::shared_ptr<AppProtect::StorageRepository> m_preMetaRepo = nullptr;

    std::shared_ptr<StorageRepositoryExtendInfo> m_preRepoExtendInfo = nullptr;
    std::shared_ptr<StorageRepositoryExtendInfo> m_curRepoExtendInfo = nullptr;
    std::shared_ptr<BackupObjectInfosInCopy> m_backupObjectInfosInCopy = nullptr;
    ScanConfig m_scanConfig {};

    OBSIndexJobType m_indexType { OBSIndexJobType::OBS_INDEX_TYPE_FULL };
    std::atomic<bool> m_isPreparing {false};
    bool m_isLastScan {false};

    std::shared_ptr<Scanner> m_scanner = nullptr;
};
}
#endif